/* =========================================================================
 *
 *   The traffic processor.
 *
 *   Development by Sedelnikov Alexander (Bigking).
 *
 * =========================================================================
 */

#include "conf.h"
#include "log.h"
#include <string.h>
#include <ctype.h>
#include <time.h>


// @todo make sections free when cfg_getnsec? check it!

//-----------------------------------------------------------------------//
// Static class vars...
cconfig             cconfig::singleton;
char                cconfig::file_name[ FILENAME_MAX ]   = "./trfprc.conf";
uint                cconfig::traffic_id_index            = 0;
ctraffic_class*     cconfig::class_traffic_start         = NULL;
ctraffic_class*     cconfig::classify_filter             = NULL;
int                 cconfig::files_type                  = FILE_TYPE_UNKNOWN;
int                 cconfig::next_cnd_id                 = 0;
int                 cconfig::prev_cnd_id                 = 0;

//-----------------------------------------------------------------------//
cconfig::cconfig()
{
    time_t         t;
    srand( time( &t ) );

    cfg = NULL;
}


//-----------------------------------------------------------------------//
int cconfig::parse( )
{
    return cconfig::singleton.parse_config_file( );
}


//-----------------------------------------------------------------------//
int cconfig::release( )
{
    if( singleton.condits != NULL )
    {
        delete []singleton.condits;
        delete []singleton.classes;
        delete []singleton.classes_reordered;
        singleton.vector_pre_cmd.clear();
        singleton.vector_post_cmd.clear();
        singleton.condits = NULL;
    }

    cfg_free( singleton.cfg );
    return 0;
}


//-----------------------------------------------------------------------//
void check_folder_format( char *dir )
{
    for( int i = strlen( dir ) - 1; i >= 0 && dir[ i ] == '/'; i-- )
        dir[ i ] = 0;
}


//-----------------------------------------------------------------------//
int cconfig::parse_config_file( )
{
    cfg_t                       *cfg_sec;
    char                        *str_ptr;

    // traffic class section
    cfg_opt_t traffic_class_opts[] =
    {
        CFG_STR ( (char*)"next",          0, CFGF_NONE ),
        CFG_STR ( (char*)"identifier",    0, CFGF_NONE ),
        CFG_BOOL( (char*)"classify_hole", cfg_false, CFGF_NONE ),
        CFG_BOOL( (char*)"process_src",   cfg_true, CFGF_NONE ),
        CFG_BOOL( (char*)"process_dst",   cfg_true, CFGF_NONE ),
        CFG_FUNC( (char*)"cnd",           &add_condition ),

        CFG_END()
    };

    // source opts
    cfg_opt_t source_opts[] =
    {
        CFG_STR ( (char*)"folder",        (char*)"./", CFGF_NONE ),
        CFG_STR ( (char*)"type",          (char*)"ipacc3", CFGF_NONE ),
        CFG_STR ( (char*)"compress",      (char*)"", CFGF_NONE ),
        CFG_STR ( (char*)"mask",          (char*)".ipacc", CFGF_NONE ),

        CFG_END()
    };

    // transactions opts
    cfg_opt_t trans_opts[] =
    {
        CFG_STR ( (char*)"folder",        (char*)"./", CFGF_NONE ),
        CFG_STR ( (char*)"table",         0, CFGF_NONE ),

        CFG_END()
    };

    // out opts
    cfg_opt_t    out_opts[] =
    {
        CFG_STR ( (char*)"folder",            (char*)"./", CFGF_NONE ),
        CFG_STR ( (char*)"stream",            (char*)"file", CFGF_NONE ),
        CFG_STR ( (char*)"format_line",       (char*)"", CFGF_NONE ),
        CFG_INT ( (char*)"filter_volume_in",  0, CFGF_NONE ),
        CFG_INT ( (char*)"filter_volume_out", 0, CFGF_NONE ),
        CFG_STR ( (char*)"server",            0, CFGF_NONE ),

        CFG_FUNC( (char*)"cmd",               &out_cmd ),
        CFG_END()
    };

    // arhive opts
    cfg_opt_t    arhive_opts[] =
    {
        CFG_STR ( (char*)"folder",        (char*)"./", CFGF_NONE ),
        CFG_STR ( (char*)"collect",       (char*)"day", CFGF_NONE ),

        CFG_END()
    };


    // root of traffic classes
    cfg_opt_t root_opts[] =
    {
        CFG_BOOL( (char*)"debug_traffic_src_not_remove", cfg_false, CFGF_NONE ),

        CFG_STR(  (char*)"pid_file",        (char*)"./trfprc.pid", CFGF_NONE ),
        CFG_STR(  (char*)"log_filename",    (char*)"./trfprc.log", CFGF_NONE ),
        CFG_INT(  (char*)"log_maxsize",     0x80000, CFGF_NONE ),
        CFG_BOOL( (char*)"log_debug",       cfg_false, CFGF_NONE ),

        CFG_STR(  (char*)"threads_count",   (char*)"1-1", CFGF_NONE ),
        CFG_STR(  (char*)"time_interval",   (char*)"3-4", CFGF_NONE ),
      CFG_FLOAT(  (char*)"distrib_low",     1.0f,  CFGF_NONE ),

        CFG_INT(  (char*)"hash_size",       16, CFGF_NONE ),
        CFG_STR(  (char*)"classify_filter", (char*)"", CFGF_NONE ),
        CFG_STR(  (char*)"start_class",     (char*)"", CFGF_NONE ),

        CFG_FUNC("include", cfg_include),

        CFG_SEC( (char*)"traffic_class",   traffic_class_opts,
                  CFGF_MULTI | CFGF_TITLE ),
        CFG_SEC( (char*)"source",          source_opts,
                  CFGF_NONE ),
        CFG_SEC( (char*)"arhive",          arhive_opts,
                  CFGF_NONE ),
        CFG_SEC( (char*)"out",             out_opts,
                  CFGF_NONE ),
        CFG_SEC( (char*)"transaction",     trans_opts,
                  CFGF_NONE ),


        CFG_END()
    };

    cfg = cfg_init( root_opts, 0 );
    if( cfg_parse( cfg, singleton.file_name ) != 0 )
    {
        THROW( e_parse, "Error while reading or parsing the configuration file!" );
    }

    // check entered parameters.
    check_folder_format( (char*)get_out_folder() );
    check_folder_format( (char*)get_transaction_folder() );
    check_folder_format( (char*)get_source_folder() );

    if( strcmp( get_out_stream(), "file" ) )
    {
        if( get_transaction_table() == NULL )
        {
            THROW( e_wrong, "[tagle] in transaction section not setted" );
        }

        if( get_out_server() == NULL )
        {
            THROW( e_wrong, "[server] in out section not setted" );
        }
    }


    // gather all information
    files_type = FILE_TYPE_UNKNOWN;

    //============================================
    //
    // Source
    //
    cfg_sec = cfg_getsec( cfg, "source" );

    // setting a file format
    str_ptr = cfg_getstr( cfg_sec, "type" );
    if( str_ptr == NULL )
    {
        THROW( e_wrong, "Input file format not setted!" );
    }
    if( !strcmp( str_ptr, "ipacc3" ) )
        files_type = FILE_TYPE_IPACC3;
    else
        THROW( e_wrong, "Unknown file format [%s]", str_ptr );

    str_ptr = cfg_getstr( cfg_sec, "compress" );
    if( str_ptr != NULL && !strcmp( str_ptr, "gzip" ) )
        files_type |= FILE_TYPE_GZ;

    // get_time_interval_max
    // get_threads_count
    if( get_time_interval_max() < 0 ||
        get_time_interval_min() < 0 )
        THROW( e_wrong, "Wrong time interval range! [min..max]" );
    if( get_threads_count_max() < 0 ||
        get_threads_count_min() < 0 )
        THROW( e_wrong, "Wrong threads count range! [min..max]" );

    // getting counters
    classes_count = cfg_size( cfg, "traffic_class" );
    condits_count = vector_condits.size();

    classes = new ctraffic_class[ classes_count ];
    condits = new ccondition    [ condits_count ];

    // filling classes without condition sequences
    for( int i = 0; i < classes_count; i++ )
    {
        cfg_sec                 = cfg_getnsec( cfg, "traffic_class", i );
        ctraffic_class  traffic = get_or_append_class( cfg_sec->title );

        str_ptr                 = cfg_getstr( cfg_sec, "identifier" );
        if( str_ptr != NULL && str_ptr[ 0 ] )
            strcpy( traffic.identifier, str_ptr );
        else
            strcpy( traffic.identifier, traffic.class_name );

        str_ptr                 = cfg_getstr( cfg_sec, "next" );
        if( str_ptr != NULL && str_ptr[ 0 ] )
            strcpy( traffic.next_class_name, str_ptr );
        else
            traffic.next_class_name[ 0 ] = 0;

        traffic.classify_hole   = cfg_getbool( cfg_sec, "classify_hole" );
        traffic.process_src     = cfg_getbool( cfg_sec, "process_src" );
        traffic.process_dst     = cfg_getbool( cfg_sec, "process_dst" );

        traffic.next_class      = NULL;
        traffic.start_condition = NULL;

        classes[ i ]            = traffic;
    }

    // prepare next class
    for( int i = 0; i < classes_count; i++ )
    {
        for( int j = 0; j < classes_count; j++ )
        {
            if( i == j )
                continue;
            if( !strcmp( classes[ i ].next_class_name, classes[ j ].class_name ) )
            {
                classes[ i ].next_class = &classes[ j ];
                break;
            }
        }
    }

    // copy conditions
    for( int i = 0; i < condits_count; i++ )
        condits[ i ] = vector_condits[ i ];

    // assign conditions
    bool  eq_founded, neq_founded;
    for( int i = 0; i < condits_count; i++ )
    {
        eq_founded  = false;
        neq_founded = false;

        for( int j = 0; j < condits_count; j++ )
        {
            if( i == j )
                continue;

            if( condits[ i ].tc_iid != condits[ j ].tc_iid )
                continue;

            if( condits[ i ].eq_state == EQ_STATE_NEXT )
            {
                if( (ulong)condits[ i ].eq_next == condits[ j ].id )
                {
                    condits[ i ].eq_next = &condits[ j ];
                    eq_founded  = true;
                }
            }

            if( condits[ i ].not_eq_state == EQ_STATE_NEXT )
            {
                if( (ulong)condits[ i ].not_eq_next == condits[ j ].id )
                {
                    condits[ i ].not_eq_next = &condits[ j ];
                    neq_founded  = true;
                }
            }
        }


        if( condits[ i ].eq_state == EQ_STATE_NEXT &&
            !neq_founded )
            {
                THROW( e_wrong, "Check condition(true) with id=[%ld] for id=[%ld]",
                        (ulong)condits[ i ].eq_next, condits[ i ].id  );

            }

        if( condits[ i ].not_eq_state == EQ_STATE_NEXT &&
            !neq_founded )
            {
                THROW( e_wrong, "Check condition(false) with id=[%ld] for id=[%ld]",
                        (ulong)condits[ i ].not_eq_next, condits[ i ].id  );
            }

    }

    // assign a conditions by the class internal identifier
    for( int i = 0; i < classes_count; i++ )
    {
        if( !strcmp( classes[ i ].class_name, cfg_getstr( cfg, "start_class" ) ) )
        {
            cconfig::class_traffic_start = &classes[ i ];
        }

        if( !strcmp( classes[ i ].class_name, cfg_getstr( cfg, "classify_filter" ) ) )
        {
            cconfig::classify_filter = &classes[ i ];
        }

        for( int j = 0; j < condits_count; j++ )
        {
            if( condits[ j ].tc_iid == classes[ i ].internal_id &&
                condits[ j ].id == 0 )
                {
                    classes[ i ].start_condition = &condits[ j ];
                    break;
                }
        }
    }

    //
    // Debug
    //
//    for( int i = 0; i < classes_count; i++ )
//    {
//        logdbg( "class\n  [%ld].identifier=[%s]self[%p]sc[%p] =next> tc[%p]",
//                 classes[ i ].internal_id,
//                 classes[ i ].identifier,
//                &classes[ i ],
//                 classes[ i ].start_condition,
//                 classes[ i ].next_class );
//
//        ccondition *cnd = classes[ i ].start_condition;
//
//        for( ; cnd != NULL &&
//               cnd->tc_iid == classes[ i ].internal_id; )
//        {
//            logdbg( " [%p] tciid=[%ld] id=[%ld] %08X %08X [%p] [%p]",
//                      cnd, cnd->tc_iid, cnd->id, cnd->net, cnd->mask,
//                      cnd->eq_next, cnd->not_eq_next );
//            cnd++;
//        }
//    }

    // @fixme @todo Make reodreding classes for index getting
    // gathering reordered classes
    classes_reordered = new ctraffic_class*[ classes_count ];

    for( int i = 0; i < classes_count; i++ )
        classes_reordered[ classes[ i ].internal_id ] = &classes[ i ];


    if( cconfig::class_traffic_start == NULL )
    {
        THROW( e_wrong, "The start traffic class [%s] not founded!.",
                 cfg_getstr( cfg, "start_class" ) );
    }

    // remove the data vectors that not need yet!
    vector_classes.clear();
    vector_condits.clear();

    return 0;
}


//-----------------------------------------------------------------------//
cconfig::~cconfig()
{
}


//-----------------------------------------------------------------------//
ctraffic_class  cconfig::get_or_append_class( const char *name )
{
    ctraffic_class                     traffic;
    bool                               found_flag = false;

    for( int i = 0; i < vector_classes.size(); i++ )
    {
        if( !strcmp( vector_classes[ i ].class_name, name ) )
        {
            traffic    = vector_classes[ i ];
            found_flag = true;
            break;
        }
    }

    if( !found_flag )
    {
        strcpy( traffic.class_name, name );
        traffic.internal_id = traffic_id_index++;

        vector_classes.push_back( traffic );
    }

    return traffic;
}


//-----------------------------------------------------------------------//
int cconfig::out_cmd( cfg_t *cfg, cfg_opt_t *opt,
                      int argc, const char **argv )
{
    if( argc != 2 )
        THROW( e_wrong, "Wrong arguments count! [cmd(type,cmd)]" );

    string  str = argv[ 1 ];

    if( !strcmp( argv[ 0 ], "begin" ) )
    {
        singleton.vector_pre_cmd.push_back( str );
    }
    else
    if( !strcmp( argv[ 0 ], "end" ) )
    {
        singleton.vector_post_cmd.push_back( str );
    }
    else
        THROW( e_wrong, "unknown type [%s]", argv[ 0 ] );

    return 0;
}


//-----------------------------------------------------------------------//
int cconfig::add_condition( cfg_t *cfg, cfg_opt_t *opt,
                            int argc, const char **argv )
{
    ccondition   cnd;
    int          ip[ 4 ], num = 0;
    static const char  *w_acc = "accept", *w_cnl = "cancel";

    static char *prev_class_name = NULL;

    if( prev_class_name != cfg->title )
    {
        prev_class_name = cfg->title;
        next_cnd_id = prev_cnd_id = 0;
    }

    cnd.type          = CND_TYPE_UNKNOWN;
    cnd.tc_iid        = singleton.get_or_append_class( cfg->title ).internal_id;

    // net and mask condition, that can be use with ip identification
    if( !strcmp( argv[ 1 ], "net" ) )
    {
        if( argc != 6 )
        {
            THROW( e_wrong, "Wrong a net condition parameters count!" );
        }

        cnd.type = CND_TYPE_NET;

        sscanf( argv[ 3 ], "%ld.%ld.%ld.%ld",
                              &ip[ 0 ],
                              &ip[ 1 ],
                              &ip[ 2 ],
                              &ip[ 3 ] );

        cnd.net =
              ip[ 0 ] |
            ( ip[ 1 ] << 8 ) |
            ( ip[ 2 ] << 16 ) |
            ( ip[ 3 ] << 24 );

        sscanf( argv[ 2 ], "%ld.%ld.%ld.%ld",
                              &ip[ 0 ],
                              &ip[ 1 ],
                              &ip[ 2 ],
                              &ip[ 3 ] );

        cnd.mask =
              ip[ 0 ] |
            ( ip[ 1 ] << 8 ) |
            ( ip[ 2 ] << 16 ) |
            ( ip[ 3 ] << 24 );
    }
    else
    {
        THROW( e_wrong, "Other condition type [%s] just not ready!", argv[ 1 ] );
    }

    if( isdigit( argv[ 0 ][ 0 ] ) )
    {
        sscanf( argv[ 0 ], "%ld", &cnd.id );

        prev_cnd_id = next_cnd_id;
        next_cnd_id = cnd.id + 1;
    }
    else
    {
        if( !strcmp( argv[ 0 ], "auto" ) )
        {
            cnd.id      = next_cnd_id;
            prev_cnd_id = next_cnd_id++;
        }
    }

    cnd.eq_next     = NULL;
    cnd.not_eq_next = NULL;

    if( isdigit( argv[ 4 ][ 0 ] ) )
    {
        cnd.eq_state = EQ_STATE_NEXT;
        sscanf( argv[ 4 ], "%ld", &num );
        cnd.eq_next  = (ccondition*)num;
    }
    else
    {
        cnd.eq_next = NULL;

        if( !strcmp( argv[ 4 ], w_acc ) )
            cnd.eq_state = EQ_STATE_ACCEPT;
        else
        if( !strcmp( argv[ 4 ], w_cnl ) )
            cnd.eq_state = EQ_STATE_CANCEL;
        else
        if( !strcmp( argv[ 4 ], "next" ) )
        {
            cnd.eq_state = EQ_STATE_NEXT;
            cnd.eq_next = (ccondition*)next_cnd_id;
        }
//        else
//        if( !strcmp( argv[ 4 ], "prev" ) )
//        {
//            cnd.eq_state = EQ_STATE_NEXT;
//            cnd.eq_next = (ccondition*)prev;
//        }
    }
    if( isdigit( argv[ 5 ][ 0 ] ) )
    {
        cnd.not_eq_state = EQ_STATE_NEXT;
        sscanf( argv[ 5 ], "%ld", &num );
        cnd.not_eq_next  = (ccondition*)num;
    }
    else
    {
        cnd.not_eq_next = NULL;

        if( !strcmp( argv[ 5 ], w_acc ) )
            cnd.not_eq_state = EQ_STATE_ACCEPT;
        else
        if( !strcmp( argv[ 5 ], w_cnl ) )
            cnd.not_eq_state = EQ_STATE_CANCEL;
        else
        if( !strcmp( argv[ 5 ], "next" ) )
        {
            cnd.not_eq_state = EQ_STATE_NEXT;
            cnd.not_eq_next = (ccondition*)next_cnd_id;
        }
//        else
//        if( !strcmp( argv[ 5 ], "prev" ) )
//        {
//            cnd.not_eq_state = EQ_STATE_NEXT;
//            cnd.not_eq_next = (ccondition*)prev;
//        }
    }



    singleton.vector_condits.push_back( cnd );

    return 0;
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Main
//
const char*     cconfig::get_file_name()
{
    return  file_name;
}


//-----------------------------------------------------------------------//
const char* cconfig::get_pid_file()
{
    return cfg_getstr( singleton.cfg, "pid_file" );
}


//-----------------------------------------------------------------------//
void            cconfig::set_file_name( const char  *fn )
{
    strncpy( file_name, fn, FILENAME_MAX );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_class_identifier( int tc_id )
{
    return singleton.classes_reordered[ tc_id ]->identifier;
}


//-----------------------------------------------------------------------//
ctraffic_class* cconfig::get_start_traffic_class()
{
    return class_traffic_start;
}


//-----------------------------------------------------------------------//
ctraffic_class* cconfig::get_classify_filter_class()
{
    return classify_filter;
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_log_filename( )
{
    if( singleton.cfg == NULL )
        return NULL;
    return cfg_getstr( singleton.cfg, "log_filename" );
}


//-----------------------------------------------------------------------//
int cconfig::get_log_maxsize()
{
    if( singleton.cfg == NULL )
        return 0;
    return cfg_getint( singleton.cfg, "log_maxsize" );
}


//-----------------------------------------------------------------------//
bool cconfig::get_log_debug()
{
    return cfg_getbool( singleton.cfg, "log_debug" ) == cfg_true;
}


//-----------------------------------------------------------------------//
int cconfig::get_threads_count_min()
{
    char *ptr = cfg_getstr( singleton.cfg, "threads_count" );

    int min = 0, max = 0;

    sscanf( ptr, "%ld..%ld", &min, &max );

    if( min > max || min < 0 || max < 0 )
        return -1;

    return min;
}


//-----------------------------------------------------------------------//
int cconfig::get_threads_count_max()
{
    char *ptr = cfg_getstr( singleton.cfg, "threads_count" );

    int min = 0, max = 0;

    sscanf( ptr, "%ld..%ld", &min, &max );

    if( max < min || min < 0 || max < 0 )
        return -1;

    return max;
}


//-----------------------------------------------------------------------//
int          cconfig::get_time_interval_min()
{
    char *ptr = cfg_getstr( singleton.cfg, "time_interval" );

    int min = 0, max = 0;

    sscanf( ptr, "%ld..%ld", &min, &max );

    if( min > max || min <= 0 || max <= 0 )
        return -1;

    return min;
}


//-----------------------------------------------------------------------//
int          cconfig::get_time_interval_max()
{
    char *ptr = cfg_getstr( singleton.cfg, "time_interval" );

    int min = 0, max = 0;

    sscanf( ptr, "%ld..%ld", &min, &max );

    if( max < min || min <= 0 || max <= 0 )
        return -1;

    return max;
}


//-----------------------------------------------------------------------//
float cconfig::get_distrib_low()
{
    return cfg_getfloat( singleton.cfg, "distrib_low" );
}


//-----------------------------------------------------------------------//
int          cconfig::get_hash_size()
{
    return cfg_getint( singleton.cfg, "hash_size" );
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Debug
//
bool         cconfig::debug_traffic_src_not_remove()
{
    return cfg_getbool( singleton.cfg, "debug_traffic_src_not_remove" );
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Source
//
const char*  cconfig::get_source_folder()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "source" );
    return cfg_getstr( cfg_sec, "folder" );
}


//-----------------------------------------------------------------------//
const int       cconfig::get_files_type()
{
    return files_type;
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_files_mask()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "source" );
    return cfg_getstr( cfg_sec, "mask" );
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Transaction
//
const char*  cconfig::get_transaction_folder()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "transaction" );
    return cfg_getstr( cfg_sec, "folder" );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_transaction_table()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "transaction" );
    return cfg_getstr( cfg_sec, "table" );
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Out
//
const char*  cconfig::get_out_format_line()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getstr( cfg_sec, "format_line" );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_out_server()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getstr( cfg_sec, "server" );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_out_stream()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getstr( cfg_sec, "stream" );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_out_folder()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getstr( cfg_sec, "folder" );
}


//-----------------------------------------------------------------------//
const int    cconfig::get_out_filter_volume_in()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getint( cfg_sec, "filter_volume_in" );
}


//-----------------------------------------------------------------------//
const int    cconfig::get_out_filter_volume_out()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "out" );
    return cfg_getint( cfg_sec, "filter_volume_out" );
}


//-----------------------------------------------------------------------//
vector<string>::const_iterator  cconfig::get_pre_cmd_begin()
{
    vector<string>::const_iterator iter = singleton.vector_pre_cmd.begin();
    return iter;
}


//-----------------------------------------------------------------------//
vector<string>::const_iterator  cconfig::get_pre_cmd_end()
{
    vector<string>::const_iterator iter = singleton.vector_pre_cmd.end();
    return iter;
}


//-----------------------------------------------------------------------//
vector<string>::const_iterator  cconfig::get_post_cmd_begin()
{
    vector<string>::const_iterator iter = singleton.vector_post_cmd.begin();
    return iter;
}


//-----------------------------------------------------------------------//
vector<string>::const_iterator  cconfig::get_post_cmd_end()
{
    vector<string>::const_iterator iter = singleton.vector_post_cmd.end();
    return iter;
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

//==============================
// Arhive
//
const char*  cconfig::get_arhive_folder()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "arhive" );
    return cfg_getstr( cfg_sec, "folder" );
}


//-----------------------------------------------------------------------//
const char*  cconfig::get_arhive_collect()
{
    cfg_t *cfg_sec = cfg_getsec( singleton.cfg, "arhive" );
    return cfg_getstr( cfg_sec, "collect" );
}
